#include <Socket.h>
#include <iostream>
#include <netdb.h>
#include "sign_kernel.h"

Socket::Socket(/* args */)
{
}

Socket::~Socket()
{
}

int Socket::CreatSocket(int domain, int type, int protocol)
{
    sockfd = socket(domain, type, protocol);
    check("socket", sockfd);
    return sockfd;
}

void Socket::CloseSocket()
{
    if (sockfd > 0)
        close(sockfd);
    printf("close socket %d\n", sockfd);
}

int Socket::getSocketFd()
{
    return sockfd;
}

int Socket::Bind(struct sockaddr_in *my_addr, socklen_t addrlen)
{
    int ret = bind(sockfd, (struct sockaddr *)my_addr, addrlen);
    check("bind", ret);
    return ret;
}

int Socket::Listen(int backlog)
{
   int ret =  listen(sockfd, backlog);
   check("listen", ret);
   return ret;
}

int Socket::Accept(struct sockaddr_in *addr, socklen_t *addrlen)
{
AGAIN:
    int ret = accept(sockfd, (struct sockaddr *)addr, addrlen);
    if(ret < 0)
    {
        if(errno == EINTR || errno == ECONNABORTED)
        {
            goto AGAIN;
        }else {
            check("accept", ret);
        }
    }
    return ret;
}

int Socket::Connect(const struct sockaddr_in *addr, socklen_t addrlen)
{
AGAIN:
    int ret = connect(sockfd, (struct sockaddr *)addr, addrlen);
    if(ret < 0)
    {
        if(ret == EINTR)
            goto AGAIN;
        else
            check("connect", ret);
    }
    return ret;
}

ssize_t Socket::Read(int fd, void *buf, size_t count)
{
AGAIN:
    int ret = read(fd, buf, count);
    if(ret < 0)
    {
        if(errno == EINTR || errno == EWOULDBLOCK)
        {
            goto AGAIN;
        }
    } 
    else if(ret == 0) 
    {
        std::cout << "对方断开链接" << std::endl;
    }
    //std::cout << "read size:" << ret << " buf:" << (char*)buf << std::endl;
    return ret;
}

ssize_t Socket::Readn(int fd, void *buf, size_t count)
{
    size_t nleft = count;//剩余未读字节数
    size_t nread = 0;//实际读到字节数
    char *ptr = (char*)buf;//读取位置
    
    while(nleft > 0)
    {
        nread = Read(fd, ptr, nleft);
        if(nread == 0)
        {
            break;
        }
        nleft -= nread;//剩余未读字节
        ptr += nread;//移动读取位置
    }
    return count - nleft;
}

#define LINE_MAX BUFSIZ
ssize_t Socket::Readline(int fd, void *buf)
{
    char c;
    char* ptr = (char*)buf;
    int nread = 0;//读取长度
    while(nread < LINE_MAX)
    {
        int ret = Read(fd, &c, 1);//读取一个字符
        if(ret == 0)
        {
            break;
        }
        *ptr++ = c;
        nread++;
        if(c == '\n')
        {
            break;
        }
        else if(c == '\0')
        {
            return nread - 1;
        }
    }
    *ptr = '\0';
    return nread;
}

ssize_t Socket::Write(int fd, const void *buf, size_t count)
{
AGAIN:
    int ret = write(fd, buf, count);
    if(ret < 0)
    {
        if(errno == EINTR)
        {
            goto AGAIN;
        }
        else {
            check("write", ret);
        }
    }
    //std::cout << "write size:" << ret << " buf:" << (char*)buf << std::endl;
    return ret;
}

ssize_t Socket::Writen(int fd, const void *buf, size_t count)
{
    size_t nleft = count;//剩余未读字节数
    size_t nwrite = 0;//实际读到字节数
    char *ptr = (char*)buf;//读取位置

    while(nleft > 0)
    {
        nwrite = Write(fd, ptr, nleft);
        nleft -= nwrite;
        ptr += nwrite;
    }
    return count;
}

ssize_t Socket::Send(int fd, const void *__buf, size_t __n, int __flags)
{
AGAIN:
    int ret = send(fd, __buf, __n, __flags);
    if(ret < 0)
    {
        if(errno == EINTR)
        {
            goto AGAIN;
        }
        else {
            check("send", ret);
        }
    }
    //std::cout << "write size:" << ret << " buf:" << (char*)buf << std::endl;
    return ret;
}

ssize_t Socket::Recv(int fd, void *__buf, size_t __n, int __flags)
{
AGAIN:
    int ret = recv(fd, __buf, __n, __flags);
    if(ret < 0)
    {
        if(errno == EINTR || errno == EWOULDBLOCK)
        {
            goto AGAIN;
        }
    } 
    else if(ret == 0) 
    {
        std::cout << "对方断开链接" << std::endl;
    }
    //std::cout << "read size:" << ret << " buf:" << (char*)buf << std::endl;
    return ret;
}

char* Socket::GetHostByName(const char *name)
{
    struct hostent *host = gethostbyname(name);
    if (!host) {
        puts("Get IP address error!");
        system("pause");
        exit(0);
    }
    //别名
    for (int i = 0; host->h_aliases[i]; i++) {
        printf("Aliases %d: %s\n", i + 1, host->h_aliases[i]);
    }
    //地址类型
    printf("Address type: %s\n", (host->h_addrtype == AF_INET) ? "AF_INET" : "AF_INET6");
    //IP地址
    for (int i = 0; host->h_addr_list[i] != nullptr; i++) {
        printf("IP addr %d: %s\n", i + 1, inet_ntoa(*(struct in_addr *)host->h_addr_list[i]));
    }
    return inet_ntoa(*(struct in_addr *)host->h_addr);
}